package com.qianfeng.smartplatform.service.impl;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qianfeng.smartplatform.cache.CategoriesCache;
import com.qianfeng.smartplatform.constants.ResultEnum;
import com.qianfeng.smartplatform.event.DeviceColorEvent;
import com.qianfeng.smartplatform.event.DevicePowerCommand;
import com.qianfeng.smartplatform.exceptions.*;
import com.qianfeng.smartplatform.mapper.DeviceMapper;
import com.qianfeng.smartplatform.pojo.Category;
import com.qianfeng.smartplatform.pojo.CheckType;
import com.qianfeng.smartplatform.pojo.Device;
import com.qianfeng.smartplatform.pojo.DeviceExample;
import com.qianfeng.smartplatform.security.BaseUser;
import com.qianfeng.smartplatform.service.DeviceService;
import com.qianfeng.smartplatform.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * Created by Jackiechan on 2021/12/26/14:19
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@Service
@Transactional
public class DeviceServiceImpl implements DeviceService {

    private ApplicationContext context;
    private CategoriesCache categoriesCache;


    private ObjectMapper objectMapper;

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Autowired
    public void setCategoriesCache(CategoriesCache categoriesCache) {
        this.categoriesCache = categoriesCache;
    }

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    private DeviceMapper deviceMapper;

    @Autowired
    public void setDeviceMapper(DeviceMapper deviceMapper) {
        this.deviceMapper = deviceMapper;
    }

    @Override
    public void AddDevice(Device device) {
        Assert.isTrue(!ObjectUtils.isEmpty(device) && !device.isEmpty(CheckType.ADD), () -> {
            throw new AddErrorException(ResultEnum.NULL_DATA);
        });

        deviceMapper.insertSelective(device);
    }

    @Override
    public void bindDevice(Device device) {
        Assert.isTrue(!ObjectUtils.isEmpty(device) && !device.isEmpty(CheckType.ADD), () -> {
            throw new AddErrorException(ResultEnum.NULL_DATA);
        });
        BaseUser user = SecurityUtils.getUser();
        device.setBindTime(new Date());
        device.setBindUserId(user.getId());
        device.setIsOnline((short) 0);
        deviceMapper.insertSelective(device);

    }

    @Override
    public void updateDevice(Device device) {
        Assert.isTrue(!ObjectUtils.isEmpty(device) && !device.isEmpty(CheckType.UPDATE), () -> {
            throw new AddErrorException(ResultEnum.NULL_DATA);
        });
        int result = deviceMapper.updateByPrimaryKeySelective(device);
        Assert.isTrue(result > 0, () -> {
            throw new UpdateErrorException(ResultEnum.DATA_NOT_EXIST);
        });
    }

    @Override
    public Device getDeviceById(String id) {
        Assert.hasText(id, () -> {
            throw new QueryDataException(ResultEnum.ID_NULL);
        });
        Device device = deviceMapper.selectByPrimaryKey(id);
        Assert.notNull(device, () -> {
            throw new QueryDataException(ResultEnum.DATA_NOT_EXIST);
        });
        return device;
    }

    @Override
    public PageInfo<Device> getAllDevices(int pageNum, int pageSize, Long sceneId) {
        Assert.isTrue(sceneId==null||sceneId >=-1, () -> {//场景id不能小于0,0 是默认场景
            throw new QueryDataException(ResultEnum.DATA_NOT_ALLOWED);
        });
        PageHelper.startPage(pageNum, pageSize);
        DeviceExample deviceExample = new DeviceExample();
        if (!ObjectUtils.isEmpty(sceneId)) {
            deviceExample.createCriteria().andSceneIdEqualTo(sceneId);//如果传递了有效的场景id,则使用场景做条件
        }
        List<Device> deviceList = deviceMapper.selectByExample(deviceExample);
        deviceList.forEach(device -> {//设置设备的id
            device.setCategory(categoriesCache.get(device.getCategyId()));
        });
        PageInfo<Device> pageInfo = new PageInfo<>(deviceList);
        return pageInfo;
    }

    @Override
    public void deleteDevices(List<String> ids) {
        Assert.notEmpty(ids, () -> {
            throw new DeleteErrorException(ResultEnum.NULL_DATA);
        });
        BaseUser user = SecurityUtils.getUser();
        DeviceExample deviceExample = new DeviceExample();
        deviceExample.createCriteria()
                .andDeviceIdIn(ids)
                .andBindUserIdEqualTo(user.getId());//需要确定删除设备的用户必须是当前用户
        int result = deviceMapper.deleteByExample(deviceExample);
        Assert.isTrue(result > 0, () -> {
            throw new DeleteErrorException(ResultEnum.DATA_NOT_EXIST);
        });
    }

    @Override
    public void sendControl(String devideId, String command) {
        Assert.isTrue(StringUtils.hasText(devideId) && StringUtils.hasText(command), () -> {
            throw new SendControlErrorException(ResultEnum.DATA_NOT_ALLOWED);
        });
        try {
            //查询设备分类,用于获取命令
            Integer categoryId = deviceMapper.getCategoryIdByDeviceId(devideId);

            Assert.notNull(categoryId, () -> {
                throw new SendControlErrorException(ResultEnum.CATEGORY_NOT_EXIST);
            });
//            Category category = categoryService.getCategoryById(categoryId);
            Category category = categoriesCache.get(categoryId);//从缓存中获取分类信息
            Assert.notNull(category, () -> {
                throw new SendControlErrorException(ResultEnum.CATEGORY_NOT_EXIST);
            });
            String commandsjson = category.getTxCommand();
            //将命令转成 map
            Map map = objectMapper.readValue(commandsjson, Map.class);
            // int result = ChatingHandler.sendControl(uuid, (String) map.get(command));
            // if (result > 0) {
            //   return;
            // }
            if (map.get(command) instanceof Map) {
                Map cMap = (Map) map.get(command);
                if (cMap != null) {
                    Integer type = (Integer) cMap.get("type");
                    if (type != null) {
                        if (type == 1) {
                            //电源控制
                            context.publishEvent(new DevicePowerCommand(devideId, (String) cMap.get("command")));
                        } else if (type == 2) {
                            //变色控制
                            context.publishEvent(new DeviceColorEvent(devideId, (String) cMap.get("command")));
                        }
                    }
                    updateControlTime(devideId);
                   return;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new SendControlErrorException(ResultEnum.DEVICE_NOT_ONLINE);
    }

    @Override
    public void updateConnectionTime(String deviceId) {
            Device device = new Device();
            device.setDeviceId(deviceId);
            device.setConnectTime(new Date());//设置连接时间
            device.setIsOnline((short) 1);//设置在线
            deviceMapper.updateByPrimaryKeySelective(device);
    }

    @Override
    public void updateoffLine(String deviceId, Short isOnline) {
        Device device = new Device();
        device.setDeviceId(deviceId);
        device.setLostConnectTime(new Date());//设置断线时间
        device.setIsOnline((short) 0);//设置离线
        deviceMapper.updateByPrimaryKeySelective(device);
    }

    @Override
    public void updateControlTime(String deviceId) {
        CompletableFuture.runAsync(()->{
            Device device = new Device();
            device.setDeviceId(deviceId);
            device.setLastControlTime(new Date());
            deviceMapper.updateByPrimaryKeySelective(device);
        });
    }
}
